﻿#define METADATA_ATTRIBUTE_MODE

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UIDesigner.ControlProviders.Bases;
using UIDesigner.FieldHandlers;
using DDW;
using System.Reflection;
using DDW.Collections;
using AFSharedLibrary;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.ComponentModel;
using System.Drawing;
using UIDesigner.ControlProviders;
using System.Windows.Forms;
using System.Globalization;

namespace UIDesigner.FieldHandlers.Bases
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
    [ControlProvider("")]
	public class FieldHandlerAttribute : System.Attribute
    {
        private float m_fPriorityNumber;
        private Type m_objMetadataAttributeType;
        private Type[] m_rgAllowableTypes;

        public Type[] AllowableTypes
        {
            get 
            { 
                return m_rgAllowableTypes; 
            }
        }

        public float PriorityNumber
        {
            get 
            { 
                return m_fPriorityNumber; 
            }
        }

        public Type MetadataAttributeType
        {
            get 
            { 
                return m_objMetadataAttributeType; 
            }
        }

        public FieldHandlerAttribute(float fPriorityNumber, Type objMetadataAttributeType)
        {
            m_fPriorityNumber = fPriorityNumber;
            m_objMetadataAttributeType = objMetadataAttributeType;
        }

        public FieldHandlerAttribute(float fPriorityNumber)
        {
            m_fPriorityNumber = fPriorityNumber;
            m_objMetadataAttributeType = null;
        }

        public FieldHandlerAttribute(float fPriorityNumber, Type objMetadataAttributeType, params Type[] rgAllowableTypes)
        {
            m_fPriorityNumber = fPriorityNumber;
            m_rgAllowableTypes = rgAllowableTypes;
            m_objMetadataAttributeType = null;
        }
    }

    public abstract class BaseFieldHandler : IFieldHandler
    {
        protected AFDesignerHost m_objHost;
        protected static List<IFieldHandler> m_rgFieldHandlers;
        
        public static event Handlers.RequestTypeHandler RequestType;
        public abstract List<string> GetControlOptions(IComponent ctrlParent, BaseNode objBase);
        public abstract Control AddControls(string strOption, IComponent ctrlParent, BaseNode objBase, int nTabIndex, List<Rectangle> rgLocationRects, List<char> rgMnemonics);
        public abstract Control AddControls(string strOption, TableLayoutPanel ctrlParent, BaseNode objBase, int nTabIndex, List<TableLayoutPanelCellPosition> rgTableLayoutPanelCellPositions, List<char> rgMnemonics);
        public abstract Control AddDefaultControls(IComponent ctrlParent, BaseNode objBase, int nTabIndex, List<Rectangle> rgLocationRects, List<char> rgMnemonics);
        public abstract Control AddDefaultControls(TableLayoutPanel ctrlParent, BaseNode objBase, int nTabIndex, List<TableLayoutPanelCellPosition> rgTableLayoutPanelCellPositions, List<char> rgMnemonics);
        public abstract Control AddPreviewDefaultControls(IComponent ctrlParent, BaseNode objBase, int nTabIndex, List<Rectangle> rgLocationRects, List<char> rgMnemonics);
        public abstract Control AddPreviewDefaultControls(TableLayoutPanel ctrlParent, BaseNode objBase, int nTabIndex, List<TableLayoutPanelCellPosition> rgTableLayoutPanelCellPositions, List<char> rgMnemonics);
        public abstract Control AddPreviewControls(string strOption, IComponent ctrlParent, BaseNode objBase, int nTabIndex, List<Rectangle> rgLocationRects, List<char> rgMnemonics);
        public abstract Control AddPreviewControls(string strOption, TableLayoutPanel ctrlParent, BaseNode objBase, int nTabIndex, List<TableLayoutPanelCellPosition> rgTableLayoutPanelCellPositions, List<char> rgMnemonics);
        public abstract bool SupportsParent(IComponent ctrlParent);

        public BaseFieldHandler(AFDesignerHost objHost)
        {
            m_objHost = objHost;
        }

        public void AddBindings(string strOption, Control ctrlBinding, BaseNode objBase, string strBindingSourceProperty)
        {
            IControlProvider objProvider = (IControlProvider)FindProvider(strOption, m_objHost);

            objProvider.AddBindings(ctrlBinding, objBase, strBindingSourceProperty);
        }

        protected void RaiseRequestType(string strName, out ConstructedTypeNode objType)
        {
            RequestType(strName, out objType);
        }

        public static Control AddControls(string strOption, IComponent ctrlParent, BaseNode objBase, bool bDefault, bool bPreview, int nTabIndex, List<Rectangle> rgLocationRects, List<char> rgMnemonics, AFDesignerHost objHost)
        {
            IControlProvider objProvider = (IControlProvider)FindProvider(strOption, objHost);

            if (objProvider.SupportsOption(strOption))
            {
                return objProvider.AddControls(strOption, ctrlParent, objBase, bDefault, bPreview, nTabIndex, rgLocationRects, rgMnemonics);
            }
            else
            {
                Debugger.Break();
                return null;
            }
        }

        public static Control AddControls(string strOption, TableLayoutPanel ctrlParent, BaseNode objBase, bool bDefault, bool bPreview, int nTabIndex, List<TableLayoutPanelCellPosition> rgTableLayoutPanelCellPositions, List<char> rgMnemonics, AFDesignerHost objHost)
        {
            IControlProvider objProvider = (IControlProvider)FindProvider(strOption, objHost);

            if (objProvider.SupportsOption(strOption))
            {
                return objProvider.AddControls(strOption, ctrlParent, objBase, bDefault, bPreview, nTabIndex, rgTableLayoutPanelCellPositions, rgMnemonics);
            }
            else
            {
                Debugger.Break();
                return null;
            }
        }

        public virtual void NegotiateLayout(string strOption, IComponent ctrlParent, BaseNode objBase, LayoutMode eLayoutMode, ref int nTabIndex, out LayoutStyle eLayoutStyle, out int nLabelAlignment, out Size szControlSize)
        {
            eLayoutStyle = LayoutStyle.Unassigned;
            nLabelAlignment = -1;
            IControlProvider objProvider = (IControlProvider)FindProvider(strOption, m_objHost);
            szControlSize = Size.Empty;

            if (objProvider.SupportsOption(strOption))
            {
                objProvider.NegotiateLayout(strOption, ctrlParent, objBase, eLayoutMode, ref nTabIndex, out eLayoutStyle, out nLabelAlignment, out szControlSize);  
            }
            else
            {
                Debugger.Break();
            }
        }

        public static IControlProvider FindProvider(string strOption, AFDesignerHost objHost)
        {
            Assembly objAssm = Assembly.GetExecutingAssembly();
            Dictionary<string, IControlProvider> rgProviders = new Dictionary<string, IControlProvider>();

            foreach (Type objType in objAssm.GetTypes())
            {
                if (objType.Namespace == "UIDesigner.ControlProviders")
                {
                    if (objType.IsClass && !objType.IsAbstract)
                    {
                        object[] rgArgs = new object[1] { objHost };
                        IControlProvider objProvider = (IControlProvider)objAssm.CreateInstance(objType.FullName, false, BindingFlags.Default, null, rgArgs, CultureInfo.CurrentCulture, null);

                        if (objProvider.SupportsOption(strOption))
                        {
                            rgProviders.Add(objType.FullName, objProvider);
                        }

                        //Debug.WriteLine(objType.FullName);
                    }
                }
            }

            return rgProviders.First().Value;
        }

        public static bool HasGetter(BaseNode objBase)
        {
            PropertyNode objProperty = objBase as PropertyNode;
            InterfacePropertyNode objIProperty = objBase as InterfacePropertyNode;
            ParamDeclNode objParm = objBase as ParamDeclNode;
            FieldNode objField = objBase as FieldNode;

            if (objProperty != null)
            {
                return objProperty.Getter != null;
            }
            else if (objIProperty != null)
            {
                return objIProperty.HasGetter;
            }
            else if (objParm != null)
            {
                return true;
            }
            else if (objField != null)
            {
                return true;
            }

            return false;
        }

        public static bool HasSetter(BaseNode objBase)
        {
            PropertyNode objProperty = objBase as PropertyNode;
            InterfacePropertyNode objIProperty = objBase as InterfacePropertyNode;
            ParamDeclNode objParm = objBase as ParamDeclNode; 
            FieldNode objField = objBase as FieldNode;

            if (objProperty != null)
            {
                return objProperty.Setter != null;
            }
            else if (objIProperty != null)
            {
                return objIProperty.HasSetter;
            }
            else if (objParm != null)
            {
                return true;
            }
            else if (objField != null)
            {
                return true;
            }

            return false;
        }

        public static string GetVariablePrefix(string strObjectType)
        {
            switch (strObjectType)
            {
                case "bool":
                    return "b";
                case "byte":
                    return "b";
                case "sbyte":
                    return "b";
                case "char":
                    return "ch";
                case "decimal":
                    return "f";
                case "double":
                    return "f";
                case "float":
                    return "f";
                case "int":
                    return "n";
                case "uint":
                    return "n";
                case "long":
                    return "n";
                case "ulong":
                    return "n";
                case "object":
                    return "obj";
                case "short":
                    return "n";
                case "ushort":
                    return "n";
                case "string":
                    return "str";
                case "DateTime":
                    return "tm";
                case "Guid":
                    return "obj";
                case "byte array":
                    return "rg";
            }

            return "m_obj";
        }

        public static string GetPrettyName(BaseNode objBase)
        {
            if (objBase.Attributes != null)
            {
                foreach (AttributeNode objAttr in objBase.Attributes)
                {
                    if (objAttr.Name.GenericIdentifier == "PrettyName")
                    {
                        StringPrimitive objString = (StringPrimitive)objAttr.Arguments[0].Expression;

                        return objString.Value;
                    }
                }
            }

            if (objBase is ParamDeclNode)
            {
                PredefinedTypeNode objType = objBase.Type as PredefinedTypeNode;
                string strPrefix;

                if (objType != null)
                {
                    strPrefix = BaseFieldHandler.GetVariablePrefix(objType.Identifier.GenericIdentifier);
                }
                else
                {
                    strPrefix = BaseFieldHandler.GetVariablePrefix("object");
                }

                if (objBase.Name.StartsWith(strPrefix))
                {
                    string strName = objBase.Name.Substring(strPrefix.Length);

                    return strName;
                }
            }

            return objBase.Name;
        }

        public static string GetPrettyDescription(BaseNode objBase)
        {
            if (objBase.Attributes != null)
            {
                foreach (AttributeNode objAttr in objBase.Attributes)
                {
                    if (objAttr.Name.GenericIdentifier == "PrettyDescription")
                    {
                        if (objAttr.Arguments.Count > 1)
                        {
                            StringPrimitive objString = (StringPrimitive)objAttr.Arguments[1].Expression;

                            return objString.Value;
                        }
                    }
                }
            }

            if (objBase is ParamDeclNode)
            {
                PredefinedTypeNode objType = objBase.Type as PredefinedTypeNode;
                string strPrefix;

                if (objType != null)
                {
                    strPrefix = BaseFieldHandler.GetVariablePrefix(objType.Identifier.GenericIdentifier);
                }
                else
                {
                    strPrefix = BaseFieldHandler.GetVariablePrefix("object");
                }

                if (objBase.Name.StartsWith(strPrefix))
                {
                    string strName = objBase.Name.Substring(strPrefix.Length);

                    return strName;
                }
            }

            return objBase.Name;
        }

        public static bool IsReadOnlyResult(BaseNode objBase)
        {
            if (objBase.Attributes != null)
            {
                foreach (AttributeNode objAttr in objBase.Attributes)
                {
                    if (objAttr.Name.GenericIdentifier == "ReadOnlyResult")
                    {
                        BooleanPrimitive objBool = (BooleanPrimitive)objAttr.Arguments[0].Expression;

                        return objBool.Value;
                    }
                }
            }

            return false;
        }

        public static bool IsWriteOnlyResult(BaseNode objBase)
        {
            if (objBase.Attributes != null)
            {
                foreach (AttributeNode objAttr in objBase.Attributes)
                {
                    if (objAttr.Name.GenericIdentifier == "WriteOnlyResult")
                    {
                        BooleanPrimitive objBool = (BooleanPrimitive)objAttr.Arguments[0].Expression;

                        return objBool.Value;
                    }
                }
            }

            return false;
        }

        public virtual bool Handles(IComponent ctrlParent, IType objType, NodeCollection<AttributeNode> rgAttributes)
        {
            if (!this.SupportsParent(ctrlParent))
            {
                return false;
            }

            foreach (Attribute objAttr in this.GetType().GetCustomAttributes(true))
            {
                FieldHandlerAttribute objFieldHandlerAttribute = objAttr as FieldHandlerAttribute;

                if (objFieldHandlerAttribute != null)
                {
                    if (objFieldHandlerAttribute.MetadataAttributeType != null)
                    {
                        foreach (AttributeNode objAttrNode in rgAttributes)
                        {
                            bool bIsAttribute = false;

                            if (objAttrNode.Name.GenericIdentifier == objFieldHandlerAttribute.MetadataAttributeType.Name)
                            {
                                bIsAttribute = true;
                            }
                            else if (objFieldHandlerAttribute.MetadataAttributeType.Name.EndsWith("Attribute"))
                            {
                                if (objAttrNode.Name.GenericIdentifier == objFieldHandlerAttribute.MetadataAttributeType.Name.Remove(objFieldHandlerAttribute.MetadataAttributeType.Name.Length - "Attribute".Length))
                                {
                                    bIsAttribute = true;
                                }
                            }

                            if (bIsAttribute)
                            {
                                bool bNoPropertySuper = true;

                                foreach (Attribute objAttr2 in objFieldHandlerAttribute.MetadataAttributeType.GetCustomAttributes(true))
                                {
                                    MetadataSuperAttribute objMetaSuperAttribute = objAttr2 as MetadataSuperAttribute;
                                    PropertySuperAttribute objPropertySuperAttribute = objAttr2 as PropertySuperAttribute;

                                    if (objMetaSuperAttribute != null)
                                    {
                                        if (objMetaSuperAttribute.SpecialHandling)
                                        {
                                            bNoPropertySuper = false;
                                        }
                                    }

                                    if (objPropertySuperAttribute != null)
                                    {
                                        bNoPropertySuper = false;

                                        if (TypeInList(objType, objPropertySuperAttribute.AllowableTypes))
                                        {
                                            return true;
                                        }
                                        else
                                        {
                                            return false;
                                        }
                                    }
                                }

                                Debug.Assert(!bNoPropertySuper);
                                return false;
                            }
                        }
                    }
                }
            }

            if (this.AllowableTypes != null && TypeInList(objType, this.AllowableTypes))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        protected static bool TypeInList(IType objIType, params Type[] rgTypes)
        {
            foreach (Type objType in rgTypes)
            {
                PredefinedTypeNode objPredefinedTypeNode = objIType as PredefinedTypeNode;

                if (objPredefinedTypeNode != null)
                {
                    if (String.Compare(objPredefinedTypeNode.GenericIdentifier, objType.Name, true) == 0)
                    {
                        return true;
                    }
                    else
                    {
                        string strType = objPredefinedTypeNode.Identifier.QualifiedIdentifier;
                        Type objRealType = GetSystemType(strType);
                        Type objBaseType;

                        if (objType.FullName == objRealType.FullName)
                        {
                            return true;
                        }

                        objBaseType = objType.BaseType;

                        while (objBaseType != null)
                        {
                            if (objRealType.FullName == objBaseType.FullName)
                            {
                                return true;
                            }

                            objBaseType = objBaseType.BaseType;
                        }

                        foreach (Type objInterface in objType.GetInterfaces())
                        {
                            if (objRealType.FullName == objInterface.FullName)
                            {
                                return true;
                            }
                        }
                    }
                }
                else
                {
                    TypeNode objTypeNode = (TypeNode)objIType;

                    // if an allowable type is an attribute itself, we are not looking for a return value of that type.
                    // Instead we are looking for a generic collection of types that are compatible with the attribute
                    // in question (has properties with those attributes)

                    if (objType.BaseType != null && objType.BaseType.FullName == "System.Attribute")
                    {
                        string strItemType;
                        string strType = objTypeNode.Identifier.QualifiedIdentifier;
                        Type objRealType = GetRealType(strType, out strItemType);

                        if (objRealType == null)
                        {
                            return false;
                        }

                        if (objRealType.FullName.StartsWith("System.Collections.Generic"))
                        {
                            ConstructedTypeNode objItemType;

                            RequestType(strItemType, out objItemType);

                            if (objItemType == null)
                            {
                                return false;
                            }
                            else
                            {
                                ClassNode objClass = objItemType as ClassNode;
                                InterfaceNode objInterface = objItemType as InterfaceNode;
                                StructNode objStruct = objItemType as StructNode; 

                                if (objClass != null)
                                {
                                    foreach (PropertyNode objProperty in objClass.Properties)
                                    {
                                        foreach (AttributeNode objAttr in objProperty.Attributes)
                                        {
                                            if (objAttr.Name.QualifiedIdentifier == objType.Name)
                                            {
                                                return true;
                                            }
                                            else
                                            {
                                                Type objAttrType = objType.Assembly.GetType(objType.Namespace + "." + objAttr.Name.QualifiedIdentifier);

                                                if (objAttrType != null)
                                                {
                                                    Type objBaseType = objAttrType.BaseType;

                                                    while (objBaseType != null)
                                                    {
                                                        if (objBaseType.FullName == objType.FullName)
                                                        {
                                                            return true;
                                                        }

                                                        objBaseType = objBaseType.BaseType;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                else if (objInterface != null)
                                {
                                    foreach (InterfacePropertyNode objProperty in objInterface.Properties)
                                    {
                                        foreach (AttributeNode objAttr in objProperty.Attributes)
                                        {
                                            if (objAttr.Name.QualifiedIdentifier == objType.Name)
                                            {
                                                return true;
                                            }
                                            else
                                            {
                                                Type objAttrType = objType.Assembly.GetType(objType.Namespace + "." + objAttr.Name.QualifiedIdentifier);

                                                if (objAttrType != null)
                                                {
                                                    Type objBaseType = objAttrType.BaseType;

                                                    while (objBaseType != null)
                                                    {
                                                        if (objBaseType.FullName == objType.FullName)
                                                        {
                                                            return true;
                                                        }

                                                        objBaseType = objBaseType.BaseType;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                else if (objStruct != null)
                                {
                                    foreach (PropertyNode objProperty in objStruct.Properties)
                                    {
                                        foreach (AttributeNode objAttr in objProperty.Attributes)
                                        {
                                            if (objAttr.Name.QualifiedIdentifier == objType.Name)
                                            {
                                                return true;
                                            }
                                            else
                                            {
                                                Type objAttrType = objType.Assembly.GetType(objType.Namespace + "." + objAttr.Name.QualifiedIdentifier);
                                                Type objBaseType = objAttrType.BaseType;

                                                while (objBaseType != null)
                                                {
                                                    if (objBaseType.FullName == objType.FullName)
                                                    {
                                                        return true;
                                                    }

                                                    objBaseType = objBaseType.BaseType;
                                                }
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    return false;
                                }
                            }
                        }
                        else if (objRealType.FullName.StartsWith("System.Collections"))
                        {
                            return true;
                        }
                    }
                    else
                    {
                        if (String.Compare(objTypeNode.Identifier.QualifiedIdentifier, objType.Name, true) == 0)
                        {
                            return true;
                        }
                        else
                        {
                            string strType = objTypeNode.Identifier.QualifiedIdentifier;
                            Type objRealType = GetRealType(strType);
                            Type objBaseType;

                            if (objRealType == null)
                            {
                                ConstructedTypeNode objConstructedType;

                                RequestType(strType, out objConstructedType);

                                if (objConstructedType == null)
                                {
                                    return false;
                                }
                                else
                                {
                                    ClassNode objClass = objConstructedType as ClassNode;
                                    InterfaceNode objInterface = objConstructedType as InterfaceNode;
                                    StructNode objStruct = objConstructedType as StructNode;

                                    if (objClass != null)
                                    {
                                        foreach (TypeNode objNode in objClass.BaseClasses)
                                        {
                                            if (objNode.GenericIdentifier == objType.Name)
                                            {
                                                return true;
                                            }
                                        }
                                    }
                                    else if (objInterface != null)
                                    {
                                        foreach (TypeNode objNode in objInterface.BaseClasses)
                                        {
                                            if (objNode.GenericIdentifier == objType.Name)
                                            {
                                                return true;
                                            }
                                        }
                                    }
                                    else if (objStruct != null)
                                    {
                                        foreach (TypeNode objNode in objStruct.BaseClasses)
                                        {
                                            if (objNode.GenericIdentifier == objType.Name)
                                            {
                                                return true;
                                            }
                                        }
                                    }

                                    return false;
                                }
                            }

                            if (objType.FullName == objRealType.FullName)
                            {
                                return true;
                            }

                            objBaseType = objType.BaseType;

                            while (objBaseType != null)
                            {
                                if (objRealType.FullName == objBaseType.FullName)
                                {
                                    return true;
                                }

                                objBaseType = objBaseType.BaseType;
                            }

                            objBaseType = objRealType.BaseType;

                            while (objBaseType != null)
                            {
                                if (objType.FullName == objBaseType.FullName)
                                {
                                    return true;
                                }

                                objBaseType = objBaseType.BaseType;
                            }

                            foreach (Type objInterface in objType.GetInterfaces())
                            {
                                if (objRealType.FullName == objInterface.FullName)
                                {
                                    return true;
                                }
                            }

                            foreach (Type objInterface in objRealType.GetInterfaces())
                            {
                                if (objType.FullName == objInterface.FullName)
                                {
                                    return true;
                                }
                            }
                        }
                    }
                }
            }

            return false;
        }

        protected static Type GetRealType(string strType)
        {
            string strOut;

            return GetRealType(strType, out strOut); 
        }

        protected static Type GetRealType(string strType, out string strItemType)
        {
            Type objType;
            Regex objRegex = new Regex(@"(?<typebase>\w+?)\<(?<itemtype>\w+?)\>");

            strItemType = null;

            if (objRegex.IsMatch(strType))
            {
                Match objMatch = objRegex.Match(strType);
                int nArgs;

                strItemType = objMatch.Groups["itemtype"].Value;
                nArgs = strItemType.Split(',').Length;

                strType = objMatch.Groups["typebase"].Value;

                objType = Type.GetType("System.Collections.Generic." + strType + "`" + nArgs.ToString());

                if (objType != null)
                {
                    return objType;
                }
            }

            objType = GetSystemType(strType);

            if (objType != null)
            {
                return objType;
            }

            objType = Type.GetType("System.Collections." + strType);

            if (objType != null)
            {
                return objType;
            }

            objType = Type.GetType("System.IO." + strType);

            if (objType != null)
            {
                return objType;
            }

            return null;
        }

        protected static Type GetSystemType(string strType)
        {
            string strFullType = null;

            switch (strType)
            {
                case "bool":
                    strFullType = "System.Boolean";
                    break;
                case "byte":	
                    strFullType = "System.Byte";
                    break;
                case "sbyte":	
                    strFullType = "System.SByte";
                    break;
                case "char":	
                    strFullType = "System.Char";
                    break;
                case "decimal":	
                    strFullType = "System.Decimal";
                    break;
                case "double":	
                    strFullType = "System.Double";
                    break;
                case "float":	
                    strFullType = "System.Single";
                    break;
                case "int":	    
                    strFullType = "System.Int32";
                    break;
                case "uint":	
                    strFullType = "System.UInt32";
                    break;
                case "long":	
                    strFullType = "System.Int64";
                    break;
                case "ulong":	
                    strFullType = "System.UInt64";
                    break;
                case "object":	
                    strFullType = "System.Object";
                    break;
                case "short":	
                    strFullType = "System.Int16";
                    break;
                case "ushort":	
                    strFullType = "System.UInt16";
                    break;
                case "string":	
                    strFullType = "System.String";
                    break;
                default:
                    strFullType = "System." + strType;
                    break;
            }

            return Type.GetType(strFullType);
        }

        public static void InstantiateHandlers(AFDesignerHost objHost)
        {
            Assembly objAssm = Assembly.GetExecutingAssembly();
            m_rgFieldHandlers = new List<IFieldHandler>();

            foreach (Type objType in objAssm.GetTypes())
            {
                if (objType.Namespace == "UIDesigner.FieldHandlers")
                {
                    if (objType.IsClass && !objType.IsAbstract)
                    {
                        object[] rgArgs = new object[1] { objHost };
                        IFieldHandler objHandler = objAssm.CreateInstance(objType.FullName, false, BindingFlags.Default, null, rgArgs, CultureInfo.CurrentCulture, null) as IFieldHandler;

                        m_rgFieldHandlers.Add(objHandler);
                    }
                }
            }
        }

        public static List<IFieldHandler> GetFieldHandlers(AFDesignerHost objHost)
        {
            if (m_rgFieldHandlers == null)
            {
                Assembly objAssm = Assembly.GetExecutingAssembly();
                m_rgFieldHandlers = new List<IFieldHandler>();

                foreach (Type objType in objAssm.GetTypes())
                {
                    if (objType.Namespace == "UIDesigner.FieldHandlers")
                    {
                        if (objType.IsClass && !objType.IsAbstract)
                        {
                            object[] rgArgs = new object[1] { objHost }; 
                            IFieldHandler objHandler = objAssm.CreateInstance(objType.FullName, false, BindingFlags.Default, null, rgArgs, CultureInfo.CurrentCulture, null) as IFieldHandler;

                            m_rgFieldHandlers.Add(objHandler);
                        }
                    }
                }
            }

            return m_rgFieldHandlers;
        }

        public static SortedDictionary<float, IFieldHandler> FindHandlers(IComponent ctrlParent, PropertyNode objProperty, AFDesignerHost objHost)
        {
            SortedDictionary<float, IFieldHandler> rgHandlers = new SortedDictionary<float, IFieldHandler>();

            foreach (IFieldHandler objHandler in BaseFieldHandler.GetFieldHandlers(objHost))
            {
                if (!objHandler.IsNested && !objHandler.IsAttributeType)
                {
                    object[] rgArgs = new object[1] { objHost }; 

                    if (objHandler.Handles(ctrlParent, objProperty.Type, objProperty.Attributes))
                    {
                        rgHandlers.Add(objHandler.PriorityNumber, objHandler);
                    }
                }
            }

            return rgHandlers;
        }

        public static SortedDictionary<float, IFieldHandler> FindHandlers(IComponent ctrlParent, InterfacePropertyNode objProperty, AFDesignerHost objHost)
        {
            SortedDictionary<float, IFieldHandler> rgHandlers = new SortedDictionary<float, IFieldHandler>();

            foreach (IFieldHandler objHandler in BaseFieldHandler.GetFieldHandlers(objHost))
            {
                if (objHandler.Handles(ctrlParent, objProperty.Type, objProperty.Attributes))
                {
                    rgHandlers.Add(objHandler.PriorityNumber, objHandler);
                }
            }

            return rgHandlers;
        }

        public static SortedDictionary<float, IFieldHandler> FindHandlers(IComponent ctrlParent, ParmItem objParmItem, AFDesignerHost objHost)
        {
            SortedDictionary<float, IFieldHandler> rgHandlers = new SortedDictionary<float, IFieldHandler>();
            ParamDeclNode objParm = objParmItem.Parm;
            PropertyNode objProperty = objParmItem.MatchingProperty;

            foreach (IFieldHandler objHandler in BaseFieldHandler.GetFieldHandlers(objHost))
            {
                if (!objHandler.IsNested && !objHandler.IsAttributeType)
                {
                    if (objHandler.Handles(ctrlParent, objParm.Type, objProperty.Attributes))
                    {
                        rgHandlers.Add(objHandler.PriorityNumber, objHandler);
                    }
                }
            }

            return rgHandlers;
        }

        public Type[] AllowableTypes
        {
            get
            {
                foreach (Attribute objAttr in this.GetType().GetCustomAttributes(true))
                {
                    FieldHandlerAttribute objFieldHandlerAttribute = objAttr as FieldHandlerAttribute;

                    if (objFieldHandlerAttribute != null)
                    {
                        return objFieldHandlerAttribute.AllowableTypes;
                    }
                }

                return new Type[0];
            }
        }

        public virtual float PriorityNumber
        {
            get
            {
                foreach (Attribute objAttr in this.GetType().GetCustomAttributes(true))
                {
                    FieldHandlerAttribute objFieldHandlerAttribute = objAttr as FieldHandlerAttribute;

                    if (objFieldHandlerAttribute != null)
                    {
                        return objFieldHandlerAttribute.PriorityNumber;
                    }
                }

                return -1;
            }
        }

        public Type MetadataAttributeType
        {
            get
            {
                return this.GetType();
            }
        }

        public bool IsNested
        {
            get 
            {
                Type objType = this.GetType();

                return objType.IsNested;
            }
        }

        public bool IsAttributeType
        {
            get 
            {
                Type objType = this.GetType();

                return objType.BaseType.Name == "Attribute";
            }
        }
    }
}
